import { EvmChainId, EvmToken } from 'sushi/evm'
import {
  http,
  createTestClient,
  formatUnits,
  parseUnits,
  publicActions,
  walletActions,
} from 'viem'
import { privateKeyToAccount, publicKeyToAddress } from 'viem/accounts'
import { type Chain, arbitrum, mainnet, polygon } from 'viem/chains'
import { localHttpUrl } from './constants'

const erc20Contract = {
  abi: [
    {
      inputs: [
        {
          internalType: 'string',
          name: 'name',
          type: 'string',
        },
        {
          internalType: 'string',
          name: 'symbol',
          type: 'string',
        },
        {
          internalType: 'uint256',
          name: 'supply',
          type: 'uint256',
        },
      ],
      stateMutability: 'nonpayable',
      type: 'constructor',
    },
  ],
  bytecode:
    '0x60806040523480156200001157600080fd5b506040518060400160405280600981526020017f66616b65546f6b656e00000000000000000000000000000000000000000000008152506040518060400160405280600281526020017f465400000000000000000000000000000000000000000000000000000000000081525081600390816200008f9190620004b7565b508060049081620000a19190620004b7565b505050620000c03369021e19e0c9bab2400000620000c660201b60201c565b620006b9565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160362000138576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200012f90620005ff565b60405180910390fd5b6200014c600083836200023360201b60201c565b806002600082825462000160919062000650565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516200021391906200069c565b60405180910390a36200022f600083836200023860201b60201c565b5050565b505050565b505050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620002bf57607f821691505b602082108103620002d557620002d462000277565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200033f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000300565b6200034b868362000300565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b600062000398620003926200038c8462000363565b6200036d565b62000363565b9050919050565b6000819050919050565b620003b48362000377565b620003cc620003c3826200039f565b8484546200030d565b825550505050565b600090565b620003e3620003d4565b620003f0818484620003a9565b505050565b5b8181101562000418576200040c600082620003d9565b600181019050620003f6565b5050565b601f82111562000467576200043181620002db565b6200043c84620002f0565b810160208510156200044c578190505b620004646200045b85620002f0565b830182620003f5565b50505b505050565b600082821c905092915050565b60006200048c600019846008026200046c565b1980831691505092915050565b6000620004a7838362000479565b9150826002028217905092915050565b620004c2826200023d565b67ffffffffffffffff811115620004de57620004dd62000248565b5b620004ea8254620002a6565b620004f78282856200041c565b600060209050601f8311600181146200052f57600084156200051a578287015190505b62000526858262000499565b86555062000596565b601f1984166200053f86620002db565b60005b82811015620005695784890151825560018201915060208501945060208101905062000542565b8683101562000589578489015162000585601f89168262000479565b8355505b6001600288020188555050505b505050505050565b600082825260208201905092915050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b6000620005e7601f836200059e565b9150620005f482620005af565b602082019050919050565b600060208201905081810360008301526200061a81620005d8565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006200065d8262000363565b91506200066a8362000363565b925082820190508082111562000685576200068462000621565b5b92915050565b620006968162000363565b82525050565b6000602082019050620006b360008301846200068b565b92915050565b61122f80620006c96000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461016857806370a082311461019857806395d89b41146101c8578063a457c2d7146101e6578063a9059cbb14610216578063dd62ed3e14610246576100a9565b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100fc57806323b872dd1461011a578063313ce5671461014a575b600080fd5b6100b6610276565b6040516100c39190610b0c565b60405180910390f35b6100e660048036038101906100e19190610bc7565b610308565b6040516100f39190610c22565b60405180910390f35b61010461032b565b6040516101119190610c4c565b60405180910390f35b610134600480360381019061012f9190610c67565b610335565b6040516101419190610c22565b60405180910390f35b610152610364565b60405161015f9190610cd6565b60405180910390f35b610182600480360381019061017d9190610bc7565b61036d565b60405161018f9190610c22565b60405180910390f35b6101b260048036038101906101ad9190610cf1565b6103a4565b6040516101bf9190610c4c565b60405180910390f35b6101d06103ec565b6040516101dd9190610b0c565b60405180910390f35b61020060048036038101906101fb9190610bc7565b61047e565b60405161020d9190610c22565b60405180910390f35b610230600480360381019061022b9190610bc7565b6104f5565b60405161023d9190610c22565b60405180910390f35b610260600480360381019061025b9190610d1e565b610518565b60405161026d9190610c4c565b60405180910390f35b60606003805461028590610d8d565b80601f01602080910402602001604051908101604052809291908181526020018280546102b190610d8d565b80156102fe5780601f106102d3576101008083540402835291602001916102fe565b820191906000526020600020905b8154815290600101906020018083116102e157829003601f168201915b5050505050905090565b60008061031361059f565b90506103208185856105a7565b600191505092915050565b6000600254905090565b60008061034061059f565b905061034d858285610770565b6103588585856107fc565b60019150509392505050565b60006012905090565b60008061037861059f565b905061039981858561038a8589610518565b6103949190610ded565b6105a7565b600191505092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6060600480546103fb90610d8d565b80601f016020809104026020016040519081016040528092919081815260200182805461042790610d8d565b80156104745780601f1061044957610100808354040283529160200191610474565b820191906000526020600020905b81548152906001019060200180831161045757829003601f168201915b5050505050905090565b60008061048961059f565b905060006104978286610518565b9050838110156104dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104d390610e93565b60405180910390fd5b6104e982868684036105a7565b60019250505092915050565b60008061050061059f565b905061050d8185856107fc565b600191505092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610616576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060d90610f25565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610685576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161067c90610fb7565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516107639190610c4c565b60405180910390a3505050565b600061077c8484610518565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146107f657818110156107e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107df90611023565b60405180910390fd5b6107f584848484036105a7565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361086b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610862906110b5565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036108da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108d190611147565b60405180910390fd5b6108e5838383610a72565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561096b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610962906111d9565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610a599190610c4c565b60405180910390a3610a6c848484610a77565b50505050565b505050565b505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610ab6578082015181840152602081019050610a9b565b60008484015250505050565b6000601f19601f8301169050919050565b6000610ade82610a7c565b610ae88185610a87565b9350610af8818560208601610a98565b610b0181610ac2565b840191505092915050565b60006020820190508181036000830152610b268184610ad3565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610b5e82610b33565b9050919050565b610b6e81610b53565b8114610b7957600080fd5b50565b600081359050610b8b81610b65565b92915050565b6000819050919050565b610ba481610b91565b8114610baf57600080fd5b50565b600081359050610bc181610b9b565b92915050565b60008060408385031215610bde57610bdd610b2e565b5b6000610bec85828601610b7c565b9250506020610bfd85828601610bb2565b9150509250929050565b60008115159050919050565b610c1c81610c07565b82525050565b6000602082019050610c376000830184610c13565b92915050565b610c4681610b91565b82525050565b6000602082019050610c616000830184610c3d565b92915050565b600080600060608486031215610c8057610c7f610b2e565b5b6000610c8e86828701610b7c565b9350506020610c9f86828701610b7c565b9250506040610cb086828701610bb2565b9150509250925092565b600060ff82169050919050565b610cd081610cba565b82525050565b6000602082019050610ceb6000830184610cc7565b92915050565b600060208284031215610d0757610d06610b2e565b5b6000610d1584828501610b7c565b91505092915050565b60008060408385031215610d3557610d34610b2e565b5b6000610d4385828601610b7c565b9250506020610d5485828601610b7c565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610da557607f821691505b602082108103610db857610db7610d5e565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610df882610b91565b9150610e0383610b91565b9250828201905080821115610e1b57610e1a610dbe565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000610e7d602583610a87565b9150610e8882610e21565b604082019050919050565b60006020820190508181036000830152610eac81610e70565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000610f0f602483610a87565b9150610f1a82610eb3565b604082019050919050565b60006020820190508181036000830152610f3e81610f02565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000610fa1602283610a87565b9150610fac82610f45565b604082019050919050565b60006020820190508181036000830152610fd081610f94565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b600061100d601d83610a87565b915061101882610fd7565b602082019050919050565b6000602082019050818103600083015261103c81611000565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b600061109f602583610a87565b91506110aa82611043565b604082019050919050565b600060208201905081810360008301526110ce81611092565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000611131602383610a87565b915061113c826110d5565b604082019050919050565b6000602082019050818103600083015261116081611124565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b60006111c3602683610a87565b91506111ce82611167565b604082019050919050565b600060208201905081810360008301526111f2816111b6565b905091905056fea2646970667358221220ca134b73ad75627d24f2c47ac4443217a02c29b9b5f932f66c17e9e0d6becf0a64736f6c63430008110033',
} as const

export async function createERC20({
  chainId,
  name = 'FakeToken',
  symbol = 'FT',
  decimals = 18,
}: {
  chainId: number
  name: string
  symbol: string
  decimals: number
}): Promise<EvmToken> {
  let chain: Chain

  if (chainId === EvmChainId.POLYGON) {
    chain = polygon
  } else if (chainId === EvmChainId.ETHEREUM) {
    chain = mainnet
  } else if (chainId === EvmChainId.ARBITRUM) {
    chain = arbitrum
  } else {
    throw new Error('Unsupported chain')
  }

  const account = privateKeyToAccount(
    '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
  )

  const client = createTestClient({
    chain,
    mode: 'anvil',
    transport: http(localHttpUrl, { timeout: 120_000 }),
  })
    .extend(walletActions)
    .extend(publicActions)

  const hash = await client.deployContract({
    ...erc20Contract,
    account,
    args: [name, symbol, BigInt(decimals)],
  })
  // await client.mine({ blocks: 1 })
  const transaction = await client.waitForTransactionReceipt({
    hash,
  })
  // const transaction = await client.getTransactionReceipt({ hash })
  if (!transaction?.contractAddress) {
    throw new Error('No contract address was found')
  }
  // const balance = await client.readContract({
  //   abi: erc20Abi,
  //   address: contractAddress,
  //   functionName: 'balanceOf',
  //   args: [publicKeyToAddress(account.publicKey)],
  // });

  return new EvmToken({
    chainId,
    address: transaction.contractAddress,
    decimals,
    symbol,
    name,
  })
}

export async function prepareERC20Balance({
  chainId,
}: {
  chainId: number
}) {
  let chain: Chain
  let usdcAddress: `0x${string}`
  let wethAddress: `0x${string}`
  const usdcAmount = parseUnits('10', 6)
  const wethAmount = parseUnits('0.0001', 18)
  if (chainId === EvmChainId.POLYGON) {
    chain = polygon
    usdcAddress = '0x2791bca1f2de4661ed88a30c99a7a9449aa84174'
    wethAddress = '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619'
  } else {
    throw new Error('Unsupported chain')
  }

  const account = privateKeyToAccount(
    '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
  )
  const publicAddress = publicKeyToAddress(account.publicKey)
  const impersonatedAccount = '0x23DefC2Ca207e7FBD84AE43B00048Fb5Cb4DB5B2'

  const client = createTestClient({
    chain,
    mode: 'anvil',
    transport: http(localHttpUrl, { timeout: 120_000 }),
  })
    .extend(walletActions)
    .extend(publicActions)

  await client.impersonateAccount({
    address: impersonatedAccount,
  })

  await client.writeContract({
    ...erc20Contract,
    address: usdcAddress,
    functionName: 'transfer',
    account: impersonatedAccount,
    args: [publicAddress, usdcAmount],
  })
  await client.writeContract({
    ...erc20Contract,
    address: wethAddress,
    functionName: 'transfer',
    account: impersonatedAccount,
    args: [publicAddress, wethAmount],
  })

  await client.stopImpersonatingAccount({
    address: impersonatedAccount,
  })
  const usdcBalance = await client.readContract({
    abi: erc20Contract.abi,
    address: usdcAddress,
    functionName: 'balanceOf',
    args: [publicAddress],
  })
  const wethBalance = await client.readContract({
    abi: erc20Contract.abi,
    address: wethAddress,
    functionName: 'balanceOf',
    args: [publicAddress],
  })
  console.log(
    `${impersonatedAccount} gave ${publicAddress} ${formatUnits(
      usdcBalance,
      6,
    )} USDC`,
  )
  console.log(
    `${impersonatedAccount} gave ${publicAddress} ${formatUnits(
      wethBalance,
      18,
    )} WETH`,
  )
}
